import turtle
import time

class EnhancedGobang:
    def __init__(self, size=15):
        # 游戏核心参数
        self.size = size  # 棋盘尺寸
        self.cell = 40    # 格子大小（像素）
        self.board = [[0 for _ in range(size)] for _ in range(size)]  # 0空/1黑/2白
        self.current_player = 1  # 黑棋先行
        self.game_over = False
        self.last_move = None  # 记录上一步位置
        self.preview_stamp = None  # 用于存储预览标记
        
        # 初始化绘图系统
        self.screen = turtle.Screen()
        self.pen = turtle.Turtle()
        self.preview_pen = turtle.Turtle()  # 专用画笔用于预览
        self.init_graphics()
        
        # 绘制棋盘（带详细格子）
        self.draw_board()
        
        # 绑定交互事件
        self.screen.onscreenclick(self.on_click)
        self.screen.onkey(self.restart, "r")
        self.screen.onkey(self.quit, "q")
        self.screen.listen()
        
        # 替代onmousemove的方案：通过定时检查鼠标位置实现预览
        self.check_mouse_position()

    def init_graphics(self):
        """初始化绘图环境"""
        # 计算窗口尺寸（确保完整显示棋盘和边缘信息）
        board_pixel = self.cell * (self.size - 1)
        window_size = board_pixel + 100  # 额外空间用于显示信息
        self.screen.setup(window_size, window_size)
        self.screen.title("五子棋 - 黑棋回合 (R重开 | Q退出)")
        self.screen.bgcolor("#F5DEB3")  # 棋盘底色（米色）
        self.screen.tracer(0)  # 手动控制刷新
        
        # 初始化主画笔
        self.pen.speed(0)
        self.pen.hideturtle()
        self.pen.pensize(1)
        
        # 初始化预览画笔
        self.preview_pen.speed(0)
        self.preview_pen.hideturtle()
        self.preview_pen.pensize(2)
        self.preview_pen.color("#999999")
        
        # 计算棋盘起始坐标（居中）
        self.start_x = -board_pixel / 2
        self.start_y = board_pixel / 2

    def draw_board(self):
        """绘制带清晰格子的棋盘"""
        # 1. 绘制外边框（加粗）
        self.pen.pensize(3)
        self.pen.color("#000000")
        self.pen.penup()
        self.pen.goto(self.start_x - 5, self.start_y + 5)
        self.pen.pendown()
        board_pixel = self.cell * (self.size - 1)
        for _ in range(2):
            self.pen.forward(board_pixel + 10)
            self.pen.right(90)
            self.pen.forward(board_pixel + 10)
            self.pen.right(90)
        self.screen.update()
        time.sleep(0.2)
        
        # 2. 绘制网格线（清晰格子边界）
        self.pen.pensize(1)
        # 横线（从左到右）
        for y in range(self.size):
            self.pen.penup()
            self.pen.goto(self.start_x, self.start_y - y * self.cell)
            self.pen.pendown()
            # 逐段绘制横线，增强格子感
            for x in range(self.size - 1):
                self.pen.forward(self.cell)
                self.screen.update()
                time.sleep(0.002)
            time.sleep(0.01)
        
        # 竖线（从上到下）
        for x in range(self.size):
            self.pen.penup()
            self.pen.goto(self.start_x + x * self.cell, self.start_y)
            self.pen.pendown()
            # 逐段绘制竖线
            for y in range(self.size - 1):
                self.pen.backward(self.cell)
                self.screen.update()
                time.sleep(0.002)
            time.sleep(0.01)
        
        # 3. 绘制星位（带标记）
        self.draw_stars()
        
        # 4. 绘制坐标标记（增强位置感）
        self.draw_coordinates()

    def draw_stars(self):
        """绘制星位（天元和四星位）"""
        stars = []
        if self.size >= 15:
            # 标准15路棋盘星位
            stars = [(3,3), (3,11), (7,7), (11,3), (11,11)]
        else:
            # 小棋盘只画天元
            mid = self.size // 2
            stars = [(mid, mid)]
        
        # 绘制星位（红色实心点）
        self.pen.penup()
        self.pen.color("#FF0000")
        for (x, y) in stars:
            screen_x = self.start_x + x * self.cell
            screen_y = self.start_y - y * self.cell
            self.pen.goto(screen_x, screen_y - 4)  # 居中调整
            self.pen.pendown()
            self.pen.begin_fill()
            self.pen.circle(4)
            self.pen.end_fill()
            self.pen.penup()
        self.screen.update()

    def draw_coordinates(self):
        """绘制坐标标记（边缘字母和数字）"""
        # 横向坐标（顶部）
        self.pen.penup()
        self.pen.color("#666666")
        for x in range(self.size):
            screen_x = self.start_x + x * self.cell
            self.pen.goto(screen_x, self.start_y + 15)
            self.pen.write(chr(65 + x), align="center", font=("Arial", 10, "normal"))
        
        # 纵向坐标（左侧）
        for y in range(self.size):
            screen_y = self.start_y - y * self.cell
            self.pen.goto(self.start_x - 15, screen_y)
            self.pen.write(str(y + 1), align="center", font=("Arial", 10, "normal"))
        self.screen.update()

    def check_mouse_position(self):
        """定时检查鼠标位置，实现预览功能（替代onmousemove）"""
        if not self.game_over:
            # 获取当前鼠标位置
            x, y = self.screen.getcanvas().winfo_pointerx(), self.screen.getcanvas().winfo_pointery()
            # 转换为turtle坐标系
            canvas = self.screen.getcanvas()
            root = canvas.winfo_toplevel()
            x -= canvas.winfo_rootx()
            y = canvas.winfo_height() - (y - canvas.winfo_rooty())
            x -= self.screen.window_width() / 2
            y -= self.screen.window_height() / 2
            
            # 清除之前的预览
            self.preview_pen.clear()
            
            # 转换为棋盘坐标
            col = round((x - self.start_x) / self.cell)
            row = round((self.start_y - y) / self.cell)
            
            # 检查是否在有效范围内且为空位
            if 0 <= col < self.size and 0 <= row < self.size and self.board[row][col] == 0:
                # 绘制预览标记（半透明圆圈）
                screen_x = self.start_x + col * self.cell
                screen_y = self.start_y - row * self.cell
                self.preview_pen.penup()
                self.preview_pen.goto(screen_x, screen_y - self.cell/4)
                self.preview_pen.pendown()
                self.preview_pen.circle(self.cell/4)
        
        self.screen.update()
        # 定时调用，模拟鼠标移动检测（每100毫秒检查一次）
        self.screen.ontimer(self.check_mouse_position, 100)

    def place_stone(self, row, col):
        """落子并显示动画和细节"""
        # 1. 记录落子
        self.board[row][col] = self.current_player
        self.last_move = (row, col)
        
        # 2. 绘制棋子（带落子动画）
        screen_x = self.start_x + col * self.cell
        screen_y = self.start_y - row * self.cell
        color = "black" if self.current_player == 1 else "white"
        border = "black"
        
        # 落子动画：从小到大
        for r in range(1, int(self.cell/2) + 1):
            self.pen.penup()
            self.pen.goto(screen_x, screen_y - r)
            self.pen.pendown()
            self.pen.color(border)
            self.pen.begin_fill()
            self.pen.circle(r)
            self.pen.color(color)
            self.pen.end_fill()
            self.screen.update()
            time.sleep(0.005)
        
        # 3. 标记最后一步（小提示点）
        self.pen.penup()
        self.pen.goto(screen_x, screen_y - 3)
        self.pen.pendown()
        self.pen.color("red" if color == "black" else "blue")
        self.pen.begin_fill()
        self.pen.circle(3)
        self.pen.end_fill()
        self.screen.update()

    def check_win(self, row, col):
        """检查是否五子连珠（带连线高亮）"""
        directions = [
            [(0, 1), (0, -1)],   # 水平
            [(1, 0), (-1, 0)],   # 垂直
            [(1, 1), (-1, -1)],  # 对角线
            [(1, -1), (-1, 1)]   # 反对角线
        ]
        
        player = self.current_player
        for dirs in directions:
            count = 1  # 当前子
            line = [(row, col)]  # 记录连珠的位置
            
            # 检查两个方向
            for dr, dc in dirs:
                r, c = row + dr, col + dc
                while 0 <= r < self.size and 0 <= c < self.size and self.board[r][c] == player:
                    count += 1
                    line.append((r, c))
                    r += dr
                    c += dc
            
            if count >= 5:
                # 高亮显示获胜连线
                self.highlight_win(line)
                return True
        return False

    def highlight_win(self, line):
        """高亮显示获胜的五子连珠"""
        self.pen.penup()
        self.pen.pensize(3)
        self.pen.color("red")
        # 转换第一个点为屏幕坐标
        r0, c0 = line[0]
        start_x = self.start_x + c0 * self.cell
        start_y = self.start_y - r0 * self.cell
        self.pen.goto(start_x, start_y)
        self.pen.pendown()
        # 连接所有连珠点
        for (r, c) in line[1:]:
            x = self.start_x + c * self.cell
            y = self.start_y - r * self.cell
            self.pen.goto(x, y)
        self.screen.update()

    def on_click(self, x, y):
        """处理落子点击"""
        if self.game_over:
            return
        
        # 转换坐标
        col = round((x - self.start_x) / self.cell)
        row = round((self.start_y - y) / self.cell)
        
        # 检查有效性
        if 0 <= col < self.size and 0 <= row < self.size and self.board[row][col] == 0:
            # 落子
            self.place_stone(row, col)
            
            # 检查胜负
            if self.check_win(row, col):
                self.game_over = True
                winner = "黑棋" if self.current_player == 1 else "白棋"
                self.show_message(f"{winner}获胜！按R重开")
                return
            
            # 切换玩家
            self.current_player = 2 if self.current_player == 1 else 1
            self.screen.title(f"五子棋 - {'黑棋' if self.current_player == 1 else '白棋'}回合 (R重开 | Q退出)")

    def show_message(self, text):
        """显示游戏信息"""
        self.pen.penup()
        self.pen.goto(0, self.start_y + 40)
        self.pen.color("red")
        self.pen.write(text, align="center", font=("SimHei", 14, "bold"))
        self.screen.update()

    def restart(self):
        """重新开始游戏"""
        self.screen.clear()
        # 清除定时器
        self.screen.ontimer(None, 100)
        # 重新初始化
        self.__init__(self.size)

    def quit(self):
        """退出游戏"""
        self.screen.bye()

    def start(self):
        """启动游戏"""
        self.screen.mainloop()

if __name__ == "__main__":
    while True:
        try:
            size = input("请输入棋盘大小(5-19，默认15): ")
            size = int(size) if size else 15
            if 5 <= size <= 19:
                game = EnhancedGobang(size)
                game.start()
                break
            else:
                print("请输入5到19之间的整数")
        except ValueError:
            print("请输入有效的数字")